﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    /*
     使用方法：
    services.AddAutoDIService();

    要注入的相应 的服务实现  IScoped ITransient ISingleton  接口
     */
    public static class ServiceCollectionExtension
    {
        public static ServiceProvider ServiceProvider { get; set; }
        /// <summary>
        /// 注入数据
        /// </summary>
        /// <param name="services"></param>
        public static IServiceCollection AddAutoDIService(this IServiceCollection services)
        {
            //var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
            string path = AppContext.BaseDirectory;
            var referencedAssemblies = Directory.GetFiles(path, "*.dll").Select(Assembly.LoadFrom).ToArray();
            Set(typeof(IScoped), path, referencedAssemblies, services);
            Set(typeof(ITransient), path, referencedAssemblies, services);
            Set(typeof(ISingleton), path, referencedAssemblies, services);
            return services;
        }

        private static void Set(Type iType, string path, Assembly[] referencedAssemblies, IServiceCollection services)
        {
            var types = referencedAssemblies
                .SelectMany(a => a.DefinedTypes)
                .Select(type => type.AsType())
                .Where(x => x != iType && iType.IsAssignableFrom(x)).ToArray();
            var implementTypes = types.Where(x => x.IsClass).ToArray();
            var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
            foreach (var implementType in implementTypes)
            {
                var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
                if (interfaceType != null)
                {
                    if (iType.Name == nameof(IScoped))
                    {
                        services.AddScoped(interfaceType, implementType);
                    }
                    else if (iType.Name == nameof(ITransient))
                    {
                        services.AddTransient(interfaceType, implementType);
                    }
                    else if (iType.Name == nameof(ISingleton))
                    {
                        services.AddSingleton(interfaceType, implementType);
                    }
                }
                else
                {
                    if (iType.Name == nameof(IScoped))
                    {
                        services.AddScoped(implementType);
                    }
                    else if (iType.Name == nameof(ITransient))
                    {
                        services.AddTransient(implementType);
                    }
                    else if (iType.Name == nameof(ISingleton))
                    {
                        services.AddSingleton(implementType);
                    }
                }
            }
        }
    }

}
